﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace QQ2564874169.Nubbo
{
    public class NubboResponse : IDisposable
    {
        private EventHandler<ResponseResult> _completed;

        public event EventHandler<ResponseResult> Completed
        {
            add
            {
                _completed += value;

                if (_responseTask.IsCompleted)
                {
                    _completed(this, _responseTask.Result);
                }
            }
            remove
            {
                if (_completed != null) _completed -= value;
            }
        }

        private Task<ResponseResult> _responseTask;
        private NubboRequest _request;
        private IResolver _resolver;
        private IServiceInvoker _invoker;
        private IObjectInput _objectInput;

        internal NubboResponse(IResolver resolver, NubboRequest request)
        {
            _request = request;
            _resolver = resolver;
            _invoker = _resolver.Resolve<IServiceInvoker>();
            _objectInput = _resolver.Resolve<IObjectInput>();
            _responseTask = Task.Run(Invoke);
        }

        private async Task<ResponseResult> Invoke()
        {
            var name = _request.GetServiceName();
            var node = _request.GetNode();
            var param = _request.ConvertToRequestParam();

            var result = await _invoker.Invoke(node, name, param);
            _completed?.Invoke(this, result);
            return result;
        }

        private static ResponseResult ThrowEx(ResponseResult result)
        {
            if (result.Error == null)
                return result;
            throw new RemoteServiceException(result.Error);
        }

        public void Wait()
        {
            var result = ThrowEx(_responseTask.Result);
            if (result.Data != null)
                throw new ResponseException("远程服务有返回值。");
        }

        public IDictionary<string, string> GetHeader()
        {
            return ThrowEx(_responseTask.Result).Header;
        }

        public T GetResult<T>()
        {
            var data = ThrowEx(_responseTask.Result).Data;
            if (data == null)
                throw new ResponseException("远程服务没有返回值。");
            return (T) _objectInput.Deserialize(typeof(T), data);
        }

        public void Dispose()
        {
            _invoker.Dispose();
            _resolver.Dispose();
        }
    }
}
